/* Copyright 2010 Michael Wenders, michaelwenders <at> gmx <dot> de

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "lcmd_includes.h"

#include "lcmd_core.h"
#include "lcmd_error.h"

bool Lcmd::quitServer = false;

Lcmd::Lcmd()
{
	logger = new lcm::log::Logger("/var/log/lcm/lcmd.log",lcm::log::LOGGER_DEBUG,lcm::log::LOGGER_INFO);
	if(!logger)
		throw LcmdError(lcm::error::SYSTEM_NO_LOGGER_CREATED,__FILE__,__LINE__); //FIXME

	config = new LcmdConfig(this, "/etc/lcm/lcmd.conf");
	if(!config)
		throw LcmdError(lcm::error::SYSTEM_NO_CONFIG_CREATED,__FILE__,__LINE__); //FIXME
}
Lcmd::~Lcmd()
{
	delete config;
	delete mysqlBackend;
	delete lcmdNetwork;
	//delete logger;
}

LcmdConfig* Lcmd::getConfig()
{
	return config;
}

LcmdMySQL* Lcmd::getMySQL()
{
	return mysqlBackend;
}

LcmdNetwork* Lcmd::getNetwork()
{
	return lcmdNetwork;
}

lcm::log::Logger* Lcmd::getLogger()
{
	return logger;
}

int Lcmd::initConfig(int argc, char* argv[])
{
	logger->write("Initialize lcmd",lcm::log::LOGGER_DEBUG);

	logger->write("Setting defaults",lcm::log::LOGGER_DEBUG);
	config->setDefaults();

	logger->write("Loading config file",lcm::log::LOGGER_DEBUG);
	config->loadFile();

	/* re-init logger class, maybe one changed loglevel or something */
	////FIXME logger->setLogLevel("debug");

	logger->write("Initialize mysql backend",lcm::log::LOGGER_DEBUG);
	/* Initialize mySQLBackend before parsing CommandLine,
	 * because mysql parameters must already be set while doing this*/

	mysqlBackend = new LcmdMySQL((Lcmd*)this, config->getMySqlServer(),
		config->getMySqlUser(),
		config->getMySqlPass(),
		config->getMySqlDb(),
		config->getMySqlPort());

	logger->write("Parsing command line",lcm::log::LOGGER_DEBUG);
	switch(this->parseCommandLine(argc,argv))
	{
		case lcm::error::CMDLINE_BREAK: // everything ok, just quit
			//logger->write("Break parsing command line, this is normal",lcm::log::LOGGER_DEBUG); // not necessary, everything's ok
			return lcm::error::CMDLINE_BREAK;

		case lcm::error::CMDLINE_MESSED_UP: // parameter messed up, show usage and quit
			logger->write("Parameter messed up",lcm::log::LOGGER_ERROR);
			this->showUsage();
			return lcm::error::CMDLINE_MESSED_UP;

		case lcm::error::CMDLINE_MISSING_OPTION:
			logger->write("Missing option after parameter",lcm::log::LOGGER_ERROR);
			return lcm::error::CMDLINE_MISSING_OPTION;

		case 0:
			return 0;

		default: // you probably never get her
			return 0;
	}
}

int Lcmd::check()
{
	/* is lcmd able to run ? */
	//FIXME
	return lcm::OK;
}

int Lcmd::parseCommandLine(int argc, char* argv[])
{
	struct struct_flags {
	    bool help;
	    bool daemonize;
	    bool version;
	    bool verbosity;
	    bool force;
	    bool sConfig;
	    bool sClients;
	    bool sGroups;
	    bool sScripts;
	    bool port;
	    bool file;
	    bool addClient;
	    bool removeClient;
	    bool addScript;
	    bool removeScript;
	    bool addGroup;
	    bool removeGroup;
	    bool group;
	    bool path;
	    bool description;
	    int whichPort;
	    string whichFile;
	    string name;			//argument of --add-group,--add-client and --add-script (and --remove-*)
	    string whichGroup;		//argument of --group
	    string whichPath;		//argument of --path
	    string whichDescription;//argument of --description
	};
	struct_flags flags{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"","","","",""};

	static const char *optString = "h?VvdfcCGSp:F:";

	static const struct option longOpts[] = {
		{ "help", no_argument, NULL, 'h' },
		{ "daemon", no_argument, NULL, 'd' },
		{ "version", no_argument, NULL, 'V' },
		{ "verbose", no_argument, NULL, 'v' },
		{ "show-config", no_argument, NULL, 'c' },
		{ "show-clients", no_argument, NULL, 'C' },
		{ "show-groups", no_argument, NULL, 'G' },
		{ "show-scripts", no_argument, NULL, 'S' },
		{ "port", required_argument, NULL, 'p' },
		{ "file", required_argument, NULL, 'F' },
		{ "force", required_argument, NULL, 'f' },
		{ "add-client", required_argument, NULL, 0 },
		{ "remove-client", required_argument, NULL, 0 },
		{ "add-script", required_argument, NULL, 0 },
		{ "remove-script", required_argument, NULL, 0 },
		{ "add-group", required_argument, NULL, 0 },
		{ "remove-group", required_argument, NULL, 0 },
		{ "group", required_argument, NULL, 0 },
		{ "path", required_argument, NULL, 0 },
		{ "description", required_argument, NULL, 0 },
		{ NULL, no_argument, NULL, 0 }
	};

	int longIndex = 0, opt = 0;

	do
	{
		opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
		switch( opt )
		{
			case 'h':
			case '?':
				flags.help = true;
				break;

			case 'd':
				flags.daemonize = true;
				break;

			case 'V':
				flags.version = true;
				break;

			case 'v':
				flags.verbosity = true;
				break;

			case 'f':
				flags.force = true;
				break;

			case 'c':
				flags.sConfig = true;
				break;

			case 'C':
				flags.sClients = true;
				break;

			case 'G':
				flags.sGroups = true;
				break;

			case 'S':
				flags.sScripts = true;
				break;

			case 'p':
				flags.port = true;
				flags.whichPort = atoi(optarg);
				break;

			case 'F':
				flags.file = true;
				flags.whichFile = optarg;
				break;

			case 0:     /* long option without a short arg */
				if( strcmp( "add-client", longOpts[longIndex].name ) == 0 )
				{
					flags.addClient = true;
					flags.name = optarg;
				}
				if( strcmp( "remove-client", longOpts[longIndex].name ) == 0 )
				{
					flags.removeClient = true;
					flags.name = optarg;
				}
				if( strcmp( "add-script", longOpts[longIndex].name ) == 0 )
				{
					flags.addScript = true;
					flags.name = optarg;
				}
				if( strcmp( "remove-script", longOpts[longIndex].name ) == 0 )
				{
					flags.removeScript = true;
					flags.name = optarg;
				}
				else if( strcmp( "add-group", longOpts[longIndex].name ) == 0 )
				{
					flags.addGroup = true;
					flags.name = optarg;
				}
				else if( strcmp( "remove-group", longOpts[longIndex].name ) == 0 )
				{
					flags.removeGroup = true;
					flags.name = optarg;
				}
				else if( strcmp( "group", longOpts[longIndex].name ) == 0 )
				{
					flags.group = true;
					flags.whichGroup = optarg;
				}
				else if( strcmp( "path", longOpts[longIndex].name ) == 0 )
				{
					flags.path = true;
					flags.whichPath = optarg;
				}
				else if( strcmp( "description", longOpts[longIndex].name ) == 0 )
				{
					flags.description = true;
					flags.whichDescription = optarg;
				}
				break;

			default:
				/* You won't actually get here. */
				break;
		}
	}while( opt != -1 );

	/* check flags and react */

	if(flags.version)
	{
		cout << LCMD_VERSION << endl;
		return lcm::error::CMDLINE_BREAK;
	}

	if(flags.verbosity)
	{
		config->increaseVerbosity();
	}

	if(flags.help)
	{
		this->showUsage();
		return lcm::error::CMDLINE_BREAK;
	}

	if(flags.force)
	{
		//nothing to do here yet
	}

	if(flags.sConfig)
	{
		//config->showConfig();
		return lcm::error::CMDLINE_BREAK;
	}

	if(flags.sClients)
	{
		mysqlBackend->showClients();
		return lcm::error::CMDLINE_BREAK;
	}

	if(flags.sGroups)
	{
		mysqlBackend->showGroups();
		return lcm::error::CMDLINE_BREAK;
	}

	if(flags.sScripts)
	{
		mysqlBackend->showScripts();
		return lcm::error::CMDLINE_BREAK;
	}

	if(flags.port)
	{
		config->setPort(flags.whichPort);
	}

	if(flags.file)
	{
		config->setFilename(flags.whichFile);
	}

	if(flags.addClient)
	{
		if(flags.group)
		{
			mysqlBackend->addClientToGroup(flags.name,flags.whichGroup);
		}
		else
		{
			mysqlBackend->addClient(flags.name);
		}
		return lcm::error::CMDLINE_BREAK;
	}

	if(flags.removeClient)
	{
		if(flags.group)
		{ // remove it from group
			mysqlBackend->removeClientFromGroup(flags.name,flags.whichGroup);
		}
		else
		{ // remove it from database
			mysqlBackend->removeClient(flags.name);
		}
		return lcm::error::CMDLINE_BREAK;
	}

	if(flags.addScript)
	{ // add a script
		if(flags.group)
		{ // add it to a group
			mysqlBackend->addScriptToGroup(flags.name,flags.whichGroup);
		}
		else
		{ // add it to the database (create one)
			if(flags.path)
			{ //got a path, that's ok
				if(flags.description)
				{ // wow, somebody wrote a description, add it too
					mysqlBackend->addScript(flags.name,flags.whichPath,flags.whichDescription);
				}
				else
				{ // no description, that's ok too
					mysqlBackend->addScript(flags.name,flags.whichPath,"");
				}
			}
			else
			{ // path is missing, return an error
				cout << "To add a script you need a path (use '--path <path>')" << endl;
				throw LcmdError(lcm::error::CMDLINE_PATH_MISSING, __FILE__, __LINE__);
			}
		} // no group flag
		return lcm::error::CMDLINE_BREAK;
	} // addScript

	if(flags.removeScript)
	{
		if(flags.group)
		{ // remove it from group
			mysqlBackend->removeScriptFromGroup(flags.name,flags.whichGroup);
		}
		else
		{ // remove it from database
			mysqlBackend->removeScript(flags.name);
		}
		return lcm::error::CMDLINE_BREAK;
	}

	if(flags.addGroup)
	{
		if(flags.description)
		{
			mysqlBackend->addGroup(flags.name,flags.whichDescription);
		}
		else
		{
			mysqlBackend->addGroup(flags.name,"");
		}
		return lcm::error::CMDLINE_BREAK;
	}

	if(flags.removeGroup)
	{
		mysqlBackend->removeGroup(flags.name);
		return lcm::error::CMDLINE_BREAK;
	}

	if(flags.group)
	{
		if(!flags.addClient && !flags.addScript)
		{
			cout << "--group needs one of '--addClient' or '--addScript'" << endl;
			throw LcmdError(lcm::error::CMDLINE_MISSING_GROUP_ARGUMENT,__FILE__,__LINE__);
		}
	}

	if(flags.path)
	{
		if(!flags.addScript)
		{
			cout << "--path needs '--add-script'" << endl;
			throw LcmdError(lcm::error::CMDLINE_MISSING_PATH_ARGUMENT, __FILE__, __LINE__);
		}
	}

	if(flags.description)
	{
		if(!flags.addGroup && !flags.addScript)
		{
			cout << "--description needs one of 'add-group' or 'add-script'" << endl;
			throw LcmdError(lcm::error::CMDLINE_MISSING_DESC_ARGUMENT, __FILE__, __LINE__);
		}
	}

	if(flags.daemonize)
	{
		config->setDaemonize(true);
	}

	return 0;
}

int Lcmd::run()
{
    string text = "Starting lcmd "; text += LCMD_VERSION; text += " (listen on ";
    text += config->getInterface(); text += ":";
    text += lcm::intToString(config->getPort()); text += ")";
	logger->write(text,lcm::log::LOGGER_INFO);

	logger->write("Initialize network backend",lcm::log::LOGGER_DEBUG);
	lcmdNetwork = new LcmdNetwork(config->getInterface(),config->getPort());
	lcmdNetwork->init();

	while(!Lcmd::quitServer) // can be triggered by pressing strg+c, or sending a signal to lcmd, view Lcmd::catchSignal()
	{
		int clientSocket; struct sockaddr_in clientData;

		// here we wait for a client to connect, this can take a while
		do
		{
			sleep(1);

			clientSocket = lcmdNetwork->getClientConnection(clientData);
			if(Lcmd::quitServer)
			{
				break;
			}

		}while( clientSocket == -1);

		if(!Lcmd::quitServer)
		{ // Incoming Connection
			threads.push_back(new pthread_t);

			// create structure to give as a argument
			struct connection client{this, clientSocket, &clientData};
			pthread_create(threads.at(threads.size()-1),NULL,handleConnection,(void*) &client);
		}
	} // </quit>

	// waiting for unfinished threads
	logger->write("Waiting for unfinished threads to finish...",lcm::log::LOGGER_INFO);
	for(unsigned int i = 0; i < threads.size(); i++)
	{
		pthread_join(*threads.at(i),NULL);
	}

	return lcm::OK;
}

void Lcmd::showUsage()
{
	cout << "lcmd version " << LCMD_VERSION << endl;
	cout << "lcmd allows to administrate linux-clients in a network" << endl;
	cout << endl;
	cout << "usage: lcmd [options]" << endl;
	cout << "   or: lcmd -m [lcmd command]" << endl;
	cout << endl;
	cout << "options:" << endl;
	cout << "\t-F || --file\t\tspecify alternate configfile" << endl;
	cout << endl;
	cout << "\t-i || --ip\t\tSpecify ip for incoming connections" << endl;
	cout << endl;
	cout << "\t-p || --port\t\tDefine a portnumber" << endl;
	cout << endl;
	cout << "\t-d || --daemonize\tFork lcmd to background" << endl;
	cout << endl;
	cout << "\t-v || --verbose\t\tIncrease verbosity" << endl;
	cout << endl;
	cout << "\t-c || --show-config\tShow running config" << endl;
	cout << endl;
	cout << "\t-C || --show-clients\tShow clients in Database" << endl;
	cout << endl;
	cout << "\t-G || --show-groups\tShow groups in Database" << endl;
	cout << endl;
	cout << "\t-S || --show-scripts\tShow scripts in Database" << endl;
	cout << endl;
	cout << "\t-V || --version\t\tShow Version" << endl;
	cout << endl;
	cout << "\t-h || --help\t\tShow Help" << endl;
	cout << endl;
	cout << "\t-?\t\t\tSame as -h" << endl;
	cout << endl;
	cout << "lcmd commands:" << endl;
	cout << "\tadd-client\t\tAdds a client to the database" << endl;
	cout << endl;
	cout << "\tremove-client\t\tRemoves a client from the database" << endl;
	cout << endl;
	cout << "\tadd-script\t\tAdds a script to the database" << endl;
	cout << endl;
	cout << "\tremove-script\t\tRemoves a script from the database" << endl;
	cout << endl;
	cout << "\tgroup\t\t\tIs used with [add|remove]-[client|script]" << endl;
	cout << "\t\t\t\tto add/remove a client to/from a group/script" << endl;
	cout << endl;
	cout << "\tpath\t\t\tIs used with --add-script" << endl;
	cout << "\t\t\t\tto define a path to a script" << endl;
	cout << endl;
	cout << "\tdescription\t\tIs used with --add-[client|script]" << endl;
	cout << "\t\t\t\tto add/remove a client to/from a group" << endl;
	cout << endl;
	cout << "Bugs to: michaelwenders@gmx.de" << endl;
}

void* Lcmd::handleConnection(void *arg)
{
	struct connection *pClient = (struct connection*)arg;
	struct connection client = *pClient;
	try
	{
		string text = "Thread "; text += lcm::intToString((pid_t) syscall (SYS_gettid)); text += ": Starting connection with client ";
		text += inet_ntoa(client.data->sin_addr); text += ":"; text += lcm::intToString(client.data->sin_port);
		text += " on socket: "; text += lcm::intToString(client.socket);
		client.lcmd->logger->write(text,lcm::log::LOGGER_INFO);

		///
		/// DEBUG!!! TEST
		///
		string testtext = "";
		RSA *rsa = lcm::ssl::initSSLPubKey("/home/regioit/lcmd.pem");
		if(!rsa)
		{
			cout << "Something wrong with RSA while getting PriKey" << endl;
		}
		lcm::ssl::readSSLSocket(client.socket, testtext,rsa);

		exit(257);

		///
		/// DEBUG!!! ENDE
		///

		string hostname = "";
		if(LcmdNetwork::initClient(client.socket,hostname) == 0)
		{
			// we didn't tell client that his hostname is ok or not
			if(!client.lcmd->mysqlBackend->doesClientExist(hostname))
			{ // client not known
				string text = "Thread "; text += lcm::intToString((pid_t) syscall (SYS_gettid));
				text += ": Client not known to lcmd ("; text += hostname; text += ")";
				client.lcmd->logger->write(text,lcm::log::LOGGER_INFO);
				lcm::writeSocket(client.socket,lcm::intToString(lcm::lcmp::LCMP_HOSTUNKNOWN));
			}
			else
			{ // client ok
				string text = "Thread "; text += lcm::intToString((pid_t) syscall (SYS_gettid));
				text += ": Client known to lcmd ("; text += hostname; text += ")";
				client.lcmd->logger->write(text,lcm::log::LOGGER_INFO);

				lcm::SVEC1D clientsGroups = client.lcmd->mysqlBackend->getClientsGroups(hostname);
				lcm::SVEC2D groupsScripts;
				lcm::SVEC1D clientsScripts;
				for(unsigned int i = 0; i < clientsGroups.size(); i++)
					groupsScripts.push_back(client.lcmd->mysqlBackend->getGroupsScripts(clientsGroups.at(i)));

				for(unsigned int i = 0; i < groupsScripts.size(); i++)
					for(unsigned int j = 0; j < groupsScripts.at(i).size(); j++)
						clientsScripts.push_back(groupsScripts.at(i).at(j));

				// find duplicated entries
				// erase duplicated entries

				text = "Thread "; text += lcm::intToString((pid_t) syscall (SYS_gettid));
				text += ": Clients's Scripts: ";
				if(clientsScripts.size() == 0)
					text += "none";
				else
				{
					for(unsigned int i = 0; i < clientsScripts.size(); i++)
					{
						text += clientsScripts.at(i); text += " ";
					}
				}
				client.lcmd->logger->write(text,lcm::log::LOGGER_INFO);


				// sending scripts
				for(unsigned int i = 0; i < clientsScripts.size(); i++)
				{
					bool mismatch = false;

					//check md5-value
					if (lcm::getMD5(client.lcmd->mysqlBackend->getScriptsPath(clientsScripts.at(i))) !=
						client.lcmd->mysqlBackend->getScriptsMD5(clientsScripts.at(i)) )
					{
						string text = "Thread "; text += lcm::intToString((pid_t) syscall (SYS_gettid));
						text += ": MD5 mismatch while trying to send script '";
						text += clientsScripts.at(i); text += "'; is: ";
						text += lcm::getMD5(client.lcmd->mysqlBackend->getScriptsPath(clientsScripts.at(i)));
						text += "; should: ";
						text += client.lcmd->mysqlBackend->getScriptsMD5(clientsScripts.at(i));
						client.lcmd->logger->write(text, lcm::log::LOGGER_WARNING);
						mismatch = true;
						if (client.lcmd->config->getSendOnMD5Mismatch())
						{
							text = "Thread "; text += lcm::intToString((pid_t) syscall (SYS_gettid));
							text += ": send it anyway (sendonmd5mismatch told us to do so)";
							client.lcmd->logger->write(text, lcm::log::LOGGER_WARNING);
						}
					}

					if (mismatch && client.lcmd->config->getSendOnMD5Mismatch())
					{
						string dummy = "";
						lcm::writeSocket(client.socket,lcm::intToString(lcm::lcmp::LCMP_SCRIPT));
						lcm::readSocket(client.socket,dummy);

						// write scriptname
						lcm::writeSocket(client.socket,clientsScripts.at(i));
						lcm::readSocket(client.socket,dummy);

						// send it
						string text = "Thread "; text += lcm::intToString((pid_t) syscall (SYS_gettid));
						text += ": Sending and executing script '"; text += clientsScripts.at(i); text += "'...";
						if(LcmdNetwork::sendTextFile(client.socket,client.lcmd->mysqlBackend->getScriptsPath(clientsScripts.at(i))) != lcm::OK)
						{
							text += "NOT OK! ";
							client.lcmd->logger->write(text,lcm::log::LOGGER_WARNING);
						}
						else
						{
							text += "OK, return Code: ";

							// get return code
							string retCode = "";
							lcm::readSocket(client.socket,retCode);
							text += retCode;
							client.lcmd->logger->write(text,lcm::log::LOGGER_INFO);

							// write data to mysql
							client.lcmd->mysqlBackend->addScriptToClient(hostname,clientsScripts.at(i),lcm::getDateTime(),lcm::stringToInt(retCode));
						}
					}
				}

				lcm::writeSocket(client.socket,lcm::intToString(lcm::lcmp::LCMP_GOODBYE));

			} // </client is ok>
		} // </initClient()>

		text = "Thread "; text += lcm::intToString((pid_t) syscall (SYS_gettid));
		text += ": Finished connection with client on socket "; text += lcm::intToString(client.socket);
		client.lcmd->logger->write(text,lcm::log::LOGGER_INFO);

		//close socket
		close(client.socket);

		//close thread
		pthread_exit(NULL);
	}
	catch(LcmdError &err)
	{
		err.logError(client.lcmd->getLogger());
	}
}

void Lcmd::catchSignal(int sig)
{
	lcm::log::Logger *logfile = new lcm::log::Logger("/var/log/lcm/lcmd.log",lcm::log::LOGGER_DEBUG,lcm::log::LOGGER_INFO);
	switch(sig)
	{
	case SIGINT:
		logfile->write("Got SIGINT",lcm::log::LOGGER_DEBUG);
		Lcmd::quitServer = true;
		break;
	case SIGHUP:
		logfile->write("Got SIGHUP",lcm::log::LOGGER_DEBUG);
		Lcmd::quitServer = true;
		break;
	case SIGTERM:
		logfile->write("Got SIGTERM",lcm::log::LOGGER_DEBUG);
		Lcmd::quitServer = true;
		break;
	default:
		string temp = "Got another signal: "; temp += lcm::intToString(sig);
		logfile->write(temp,lcm::log::LOGGER_DEBUG);
	}

}

int Lcmd::prepare()
{
	if(config->getDaemonize())
	{
		// daemonize
		if (getppid() == 1)
		{
			logger->write("lcmd is already daemonized",lcm::log::LOGGER_WARNING);
		}

		int i = fork();

		if (i < 0)
		{
			logger->write("cannot daemonize lcmd",lcm::log::LOGGER_PANIC);
			throw LcmdError(lcm::error::SYSTEM_CANNOT_DAEMONIZE, __FILE__, __LINE__);
		}

		if (i > 0)
		{
			// this is just for the parent process
			exit(0); /* parent exits */
		}

		// some other things
		setsid(); /* obtain a new process group */

		for (i = getdtablesize(); i >= 0; --i)
			close(i); /* close all descriptors */

		i = open("/dev/null",O_RDWR); dup(i); dup(i); /* handle standart I/O */

		logger->write("process daemonized", lcm::log::LOGGER_DEBUG);
	}
	else
		logger->write("process not daemonized, as specified in config file or through command line",lcm::log::LOGGER_DEBUG);

	// change working directory
	chdir("/srv/"); //FIXME

	umask(027); /* set newly created file permissions */

	// create lock file if it does not exist
	int lfp = open(config->getLockFile().c_str(), O_RDWR|O_CREAT, 0640);

	if (lfp < 0)
	{
		logger->write("cannot create lock file, do you have permissions to create the lock file?",lcm::log::LOGGER_PANIC);
		throw LcmdError(lcm::error::SYSTEM_CANNOT_CREATE_LOCK_FILE, __FILE__, __LINE__);
	}

	if (lockf(lfp, F_TLOCK, 0) < 0)
	{
		logger->write("cannot set lock to lock file",lcm::log::LOGGER_PANIC);
		throw LcmdError(lcm::error::SYSTEM_CANNOT_SET_LOCK, __FILE__, __LINE__);
	}

	char str[10];
	sprintf(str,"%d\n",getpid());
	write(lfp,str,strlen(str)); // write pid to lockfile

	// create pid file if it does not exist
	fstream pf(config->getPidFile().c_str(), ios::in); //does file exists?
	if(pf)
	{
		string temp = config->getPidFile();
		temp += " already exists, lcmd won't start. Please make sure that no other instance of lcmd is running!";
		logger->write(temp,lcm::log::LOGGER_PANIC);
		throw LcmdError(lcm::error::SYSTEM_ALREADY_RUNNING, __FILE__, __LINE__);
	}

	pf.open(config->getPidFile().c_str(), ios::out | ios::trunc);
	if(!pf)
	{
		logger->write("cannot create pid file!", lcm::log::LOGGER_PANIC);
		throw LcmdError(lcm::error::SYSTEM_CANNOT_CREATE_PID_FILE, __FILE__, __LINE__);
	}
	else
		pf << getpid() << endl;

	// signal handling
	signal(SIGCHLD,catchSignal); /* ignore child */
	signal(SIGTSTP,catchSignal); /* ignore tty signals */
	signal(SIGTTOU,catchSignal);
	signal(SIGTTIN,catchSignal);
	signal(SIGINT,catchSignal);

	signal(SIGHUP,catchSignal); /* catch hangup signal */
	signal(SIGTERM,catchSignal); /* catch kill signal */

	return 0;
}

int Lcmd::finishServer()
{
	//delete lockfile
	remove(config->getLockFile().c_str());

	//delete pidfile
	remove(config->getPidFile().c_str());

	return 0;
}




